<?php
/**
 * Created by PhpStorm.
 * User: Admin
 * Date: 2020-08-01
 * Time: 下午 08:38
 */
namespace Lib;

abstract class Cmd extends Injector {
    /**
     * 以:开头位短参数
     * 以:结尾位必选参数
     * @var string[] 
     */
    protected $_options = [''];
    protected $_params;
    protected $_argv;
    
    public function prepareParams($options) {
        $this->_argv = $options['argv'];
        $this->_params = $options['params'];
        
        $optionAllow = [];
        $this->_options = array_merge(array_filter($this->_options), ['help']);
        $longOptionRequire = [];
        
        foreach ($this->_options as $option) {
            $option = trim($option);

            /**
             * 以冒号开头的位短参数
             */
            if($option[0] == ':') {
                $optionAllow = array_merge($optionAllow, str_split(trim($option, ':')));
            } else {
                /**
                 * 以冒号结束表示必选参数
                 */
                if (substr($option, -1) == ':') {
                    $option = trim($option, ':');
                    $longOptionRequire []= $option;
                }

                $optionAllow []= $option;
            }
        }

        $optionAllow = array_unique($optionAllow);
        $optionAllow = array_flip($optionAllow);
        $longOptionRequire = array_unique($longOptionRequire);
        
        foreach ($this->_params as $key => $param) {
            if(!isset($optionAllow[$key])) {
                $this->writeError("不支持的参数 '$key'");
            }
        }
        
        foreach ($longOptionRequire as $key) {
            if(!isset($options[$key])) {
                $this->writeError("缺少参数 '$key'");
            }
        }
    }

    public function write($msg) {
        echo "$msg";
    }

    public function writeLn() {
        echo PHP_EOL;
    }
    
    public function writeError($error, $exit=true) {
        echo "错误: $error" . PHP_EOL;
        
        if($exit) {
            exit;
        }
    }
    
    public function writeSuccess($msg, $exit=true) {
        echo "$msg" . PHP_EOL;
        
        if($exit) {
            exit;
        }
    }
    
    public function writeInfo($msg) {
        echo "$msg" . PHP_EOL;
    }
    
    public function existParam($key) {
        return array_key_exists($key, $this->_params);
    }
    
    public function getAllParams() {
        return $this->_params;
    }
    
    public function getParam($key, $default=null) {
        return $this->_params[$key]?$this->_params[$key]:$default;
    }
    
    public function getArgv($key, $default=null) {
        return $this->_argv[$key]?$this->_argv[$key]:$default;
    }
    
    public function getAllArgv() {
        return $this->_argv;
    }
    
    public function getCmdOptions() {
        return [
            'argv' => $this->_argv,
            'params' => $this->_params
        ];
    }
    
    public function inputSecurely($msg=null, $showChar='*') {
        static $signIns = false;
        
        $oldStyle = shell_exec('stty -g');
        
        if(!$signIns) {
            $signIns = true;
            pcntl_signal(SIGINT, function() use($oldStyle) {
                $this->writeLn();
                shell_exec("stty $oldStyle");
                exit;
            });
            pcntl_signal_dispatch();
        }
        
        if($msg) {
            $this->write($msg);
        }
        
        shell_exec('stty -echo -icanon min 1 time 0');
        $string = '';
        stream_set_blocking(STDIN, false);

        declare(ticks=1);
        
        while(true) {
            $char = $this->inputChar();
            
            if($char == false) {
                usleep(50);
                continue;
            }

            if($char == "\n") {
                break;
            }
            
            if(ord($char) == 127) {
                $len = strlen($string);
                $string = substr($string, 0, $len-1);
                $shwoChars = str_repeat($showChar, $len-1);
                $this->write("\r$msg$shwoChars ");
                $this->write("\r$msg$shwoChars");
                continue;
            }
           
            $string .= $char;
           
            if($showChar) {
                $this->write($showChar);
            }
        }

        shell_exec("stty $oldStyle");
        stream_set_blocking(STDIN, true);
        $this->writeLn();
        return $string;
    }
    
    public function inputChar($stream=STDIN) {
        return fgetc($stream);
    }
    
    public function inputString($msg=null) {
        if($msg) {
            $this->write($msg);
        }
        
        return fgets(STDIN);
    }
    
    public function main() {
        
    }
    
    public function help() {
        
    }
}